package com.bitin.adorn.common.orm;

import org.springframework.data.jpa.domain.Specification;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Date;

/**
 * <p>
 *
 * </p>
 *
 * @author: Mr.Lu
 * @since: 2024/12/05 17:50
 */
public final class JPAPredicateHelper {
    // 时区对象
    private static final ZoneOffset ZONE_OFFSET = ZoneOffset.of("+8");
    // 日期时间格式化对象
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 获取对应属性的值所在区间
     */
    public static Specification isBetween(String attribute, int min, int max) {
        return (root, query, builder) -> builder.between(root.get(attribute), min, max);
    }

    public static Specification isBetween(String attribute, double min, double max) {
        return (root, query, builder) -> builder.between(root.get(attribute), min, max);
    }

    /**
     * 比较日期区间
     *
     * @param attribute 实体中的字段名称
     * @param min       最小日期值
     * @param max       最大日期值
     * @return 查询条件的封装对象
     */
    public static Specification isBetween(String attribute, Date min, Date max) {
        LocalDateTime lmin = LocalDateTime.ofInstant(min.toInstant(), ZONE_OFFSET);
        LocalDateTime lmax = LocalDateTime.ofInstant(max.toInstant(), ZONE_OFFSET);
        //return (root, query, builder) -> builder.between(root.get(attribute), min, max);
        return (root, query, builder) -> builder.between(root.get(attribute).as(String.class), DATE_TIME_FORMATTER.format(lmin), DATE_TIME_FORMATTER.format(lmax));
    }

    /**
     * 比较任意值的区间
     *
     * @param attribute 实体中的字段名称
     * @param min       最小值
     * @param max       最大值
     * @param <T>
     * @return 查询条件的封装对象
     */
    public static <T extends Comparable> Specification between(String attribute, T min, T max) {
        return (root, query, builder) -> builder.between(root.get(attribute), min, max);
    }

    /**
     * 完全模糊匹配 ， like %?1%
     *
     * @param attribute 实体中的字段名称
     * @param value     固定值
     * @return 查询条件的封装对象
     */
    private static Specification like(String attribute, String value) {
        return likeBuild(attribute, "%" + value + "%");
    }

    /**
     * 模糊匹配头部, like %?1
     *
     * @param attribute 实体中的字段名称
     * @param value     固定值
     * @return 查询条件的封装对象
     */
    public static Specification likeLeft(String attribute, String value) {
        return likeBuild(attribute, "%" + value);
    }

    /**
     * 模糊匹配尾部, like ?1%
     *
     * @param attribute 实体中的字段名称
     * @param value     固定值
     * @return 查询条件的封装对象
     */
    public static Specification likeRight(String attribute, String value) {
        return likeBuild(attribute, value + "%");
    }

    private static Specification likeBuild(String attribute, String value) {
        return (root, query, builder) -> builder.like(root.get(attribute), value );
    }

    /**
     * 字段为null条件
     * @param attribute 实体中的字段名称
     * @return 查询条件的封装对象
     */
    public static Specification isNull(String attribute){
        return (root, query, builder) -> builder.isNull(root.get(attribute));
    }

    /**
     * 字段不为null条件
     * @param attribute 实体中的字段名称
     * @return 查询条件的封装对象
     */
    public static Specification isNotNull(String attribute){
        return (root, query, builder) -> builder.isNotNull(root.get(attribute));
    }

    /**
     * 通过属性名和集合实现 in 查询
     */
    public static <T> Specification in(String attribute, Collection<T> collection) {
        return (root, query, builder) ->root.get(attribute).in(collection);
    }

    /**
     * in 条件
     * @param attribute
     * @param values
     * @return
     */
    public static <T> Specification in(String attribute, T...values){
        return (root, query, builder) -> root.get(attribute).in(values);
    }

    /**
     * 任意值相等比较
     * 某字段的值等于 value 的查询条件
     *
     * @param attribute 实体中的字段名称
     * @param value     比较值
     * @return 查询条件的封装对象
     */
    public static <T> Specification eq(String attribute, T value) {
        return (root, query, builder) -> builder.equal(root.get(attribute), value);
    }

    /**
     * 数值大于比较
     *
     * @param attribute 实体中的字段名称
     * @param value     比较值
     * @param <T>
     * @return 查询条件的封装对象
     */
    public static <T extends Number> Specification gt(String attribute, T value) {
        return (root, query, builder) -> builder.gt(root.get(attribute).as(Number.class), value);
    }

    public static <T extends Comparable> Specification gt(String attribute, T value) {
        return (root, query, builder) -> builder.greaterThan(root.get(attribute), value);
    }

    /**
     * 数值大于等于比较
     * 通过属性名构建大于等于 Value 的查询条件
     *
     * @param attribute 实体中的字段名称
     * @param value     比较值
     * @param <T>
     * @return 查询条件的封装对象
     */
    public static <T extends Comparable> Specification ge(String attribute, T value) {
        return (root, query, builder) -> builder.greaterThanOrEqualTo(root.get(attribute), value);
    }

    /**
     * 数值小于比较
     *
     * @param fieldName 实体中的字段名称
     * @param value     比较值
     * @param <T>
     * @return 查询条件的封装对象
     */
    public static <T extends Number> Specification lt(String fieldName, T value) {
        return (root, query, builder) -> builder.lt(root.get(fieldName).as(Number.class), value);
    }

    /**
     * 数值小于等于比较
     *
     * @param fieldName 实体中的字段名称
     * @param value     比较值
     * @param <T>
     * @return 查询条件的封装对象
     */
    public static <T extends Comparable> Specification le(String fieldName, T value) {
        return (root, query, builder) -> builder.lessThanOrEqualTo(root.get(fieldName), value);
    }
}
